﻿//-----------------------------------------------------------------------
// <copyright>
// This file is subject to the terms and conditions of the Microsoft Public License (MS-PL).
// See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL for more details.
// </copyright>
//----------------------------------------------------------------------- 
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Diagnostics;

namespace Fulcrum.DispatcherProxies
{
    public static class CSharpHelp
    {
        public static string CreateMethodName(string baseName, ICollection<ParameterInfo> parameters)
        {
            var methodName = new StringBuilder();
            methodName.Append(baseName);

            foreach (var parameter in parameters)
            {
                var parameterTypeName = parameter.ParameterType.Name;

                // The parameter name will contain the ` character if it is a genric type
                // Search and replace it with the _ character to ensure that the generated proxy is compilable
                if (parameterTypeName.Contains("`"))
                {
                    parameterTypeName = parameterTypeName.Replace("`", "_");
                }

                methodName.Append(parameterTypeName);
            }

            return methodName.ToString();
        }

        public static string CreateParameterDeclaration(ICollection<ParameterInfo> parameters)
        {
            return CreateParameterDeclaration(parameters, String.Empty);
        }

        public static string CreateParameterDeclaration(ICollection<ParameterInfo> parameters, string parameterPrefix)
        {
            var @params = new StringBuilder();

            foreach (var parameter in parameters)
            {
                AddToList(@params, "{0} {1}{2}", CSharpHelp.GetFullTypeName(parameter.ParameterType), parameterPrefix, parameter.Name);
            }

            return @params.ToString();
        }

        public static string CreateParameterList(ICollection<ParameterInfo> parameters)
        {
            return CreateParameterList(parameters, String.Empty);
        }

        public static string CreateParameterList(ICollection<ParameterInfo> parameters, string parameterPrefix)
        {
            var @params = new StringBuilder();

            foreach (var parameter in parameters)
            {
                AddToList(@params, "{0}{1}", parameterPrefix, parameter.Name);
            }

            return @params.ToString();
        }

        public static void AddToList(StringBuilder sb, string text)
        {
            if (sb.Length != 0)
            {
                sb.AppendFormat(", {0}", text);
            }
            else
            {
                sb.Append(text);
            }
        }

        public static void AddToList(StringBuilder sb, string format, params object[] args)
        {
            string text = String.Format(format, args);
            AddToList(sb, text);
        }

        public static string GetFullTypeName(Type type)
        {
            Debug.Assert(type != null);

            if (type == typeof(void))
            {
                return "void";
            }
            else if (type.IsGenericType)
            {
                var genericParams = type.GetGenericArguments();
                var genericParamList = new StringBuilder();

                foreach (var param in genericParams)
                {
                    AddToList(genericParamList, GetFullTypeName(param));
                }

                string fullName = GetName(type);
                var startOfGenericManagle = fullName.IndexOf('`');
                string genericFullName = fullName.Substring(0, startOfGenericManagle);

                var typeName = String.Format("{0}<{1}>", genericFullName, genericParamList);
                return typeName;
            }
            else
            {
                return GetName(type);
            }
        }

        private static string GetName(Type type)
        {
            if (type.FullName != null)
            {
                return type.FullName;
            }
            else
            {
                return type.Name;
            }
        }

        public static string GetMethodName(MethodInfo methodInfo)
        {
            var name = methodInfo.Name;

            if (methodInfo.ContainsGenericParameters)
            {
                var genericParams = methodInfo.GetGenericArguments();
                var genericParamList = new StringBuilder();

                foreach (var param in genericParams)
                {
                    AddToList(genericParamList, GetFullTypeName(param));
                }

                string genericFullName = methodInfo.Name;

                name = String.Format("{0}<{1}>", genericFullName, genericParamList);
            }

            return name;
        }
    }
}
